#include "lib/global.h"
#include "memory/memory.h"
#include "memory/bitmap.h"
#include "lib/memctrl.h"
//三个内存池分别代表内核虚拟池， 用户虚拟池和实际物理池
pool VKernelPool, VUserPool, RMemPool;
void InitMemory()
{
    uint32_t heapMemory = SYS_MEMORY_SIZE - Unit_1M;
    uint32_t bitmapSize = ROUNDUP(heapMemory, Unit_32K) / Unit_32K;
    //初始化三个内存池的大小和起始位置
    InitBitmap(&VKernelPool.pool_bitmap, bitmapSize, (ptr_t)POOL_BASE);
    InitBitmap(&VUserPool.pool_bitmap, bitmapSize, (ptr_t)POOL_BASE + bitmapSize);
    InitBitmap(&RMemPool.pool_bitmap, bitmapSize, (ptr_t)POOL_BASE + 2 * bitmapSize);
    VKernelPool.memStart = (ptr_t)0xc1000000;
    VUserPool.memStart = (ptr_t)0x01000000;
    RMemPool.memStart = (ptr_t)0x00100000;
    return ;
}
ptr_t ApplyMemory(uint32_t PoolType, uint32_t bytesSize)
{
    ptr_t allocVMemAddr;
    ptr_t allocRMemAddr;
    uint32_t pageCnt = ROUNDUP(bytesSize, Unit_32K) / Unit_32K;
    //先分配物理内存，再分配虚拟内存
    allocRMemAddr = RMemPool.memStart + GetBitsBlock(&RMemPool.pool_bitmap, pageCnt) * Unit_4K;
    if(allocRMemAddr == NULL){
         return NULL;
    }
    if(PoolType == 0){
        allocVMemAddr = VKernelPool.memStart + GetBitsBlock(&VKernelPool.pool_bitmap, pageCnt) * Unit_4K;
    }else{
        allocVMemAddr = VUserPool.memStart + GetBitsBlock(&VUserPool.pool_bitmap, pageCnt) * Unit_4K;
    }
    AddPageMap(allocVMemAddr, allocRMemAddr, pageCnt);
    return allocVMemAddr;
}
void FreeMemory(uint32_t PoolType, ptr_t BlockPos, uint32_t bytesSize)
{
    uint32_t pageCnt = ROUNDUP(bytesSize, Unit_32K) / Unit_32K;
    ptr_t Real_ptr = (ptr_t)REAL_ADDR(INT_T(BlockPos));
    uint32_t RealBitsStart = (Real_ptr - RMemPool.memStart) / Unit_4K;
    uint32_t VirtualBitsStart;
    //直接释放物理内存
    FreeBitsBlock(&RMemPool.pool_bitmap, RealBitsStart, pageCnt);
    //选择释放内核和用户的内存
    if(PoolType == 0){
        VirtualBitsStart = (BlockPos - VKernelPool.memStart) / Unit_4K;
        FreeBitsBlock(&VKernelPool.pool_bitmap, VirtualBitsStart, pageCnt);
    }else{
        VirtualBitsStart = (BlockPos - VUserPool.memStart) / Unit_4K;
        FreeBitsBlock(&VUserPool.pool_bitmap, VirtualBitsStart, pageCnt);
    }
    return ;
}
void AddPageMap(ptr_t allocVMemAddr, ptr_t allocRMemAddr, uint32_t pageCnt)
{
    uint32_t PagePde;
    uint32_t PagePte;
    ptr_t PdeRAddr;
    uint32_t i;
    for(i = 0; i < pageCnt; ++i, allocVMemAddr += Unit_4K){
        //对于要分配的每一个页都要建立页表映射
        PagePde = PDE_ADDR(INT_T(allocVMemAddr));
        if(PTR32_R(PagePde) == 0){
            //如果页目录还没有建立，就为它申请内存并初始化
            PdeRAddr = RMemPool.memStart + GetBitsBlock(&RMemPool.pool_bitmap, 1) * Unit_4K;
            PTR32_R(PagePde) = INT_T(PdeRAddr) | PAGE_US_U | PAGE_RW_W | PAGE_P;
            memset_S((ptr_t)((0x3ff << PDE_INDEX_OFFSET) | (BitVector(PagePde, 2, 11) << 12)), 0, 4096);
        }
        PagePte = PTE_ADDR(INT_T(allocVMemAddr));
        PTR32_R(PagePte) = INT_T(allocRMemAddr) | PAGE_US_U | PAGE_RW_W | PAGE_P;
    }
    return ;
}
ptr_t malloc_sys(uint32_t PoolType, uint32_t bytesSize)
{
    uint32_t header_size = sizeof(struct Memory_Ptr_Header);
    ptr_t fullPtr = ApplyMemory(PoolType, bytesSize + header_size);
    struct Memory_Ptr_Header *ptr2Head = fullPtr;
    ptr2Head->size = bytesSize;
    ptr2Head->type = PoolType;
    return fullPtr + header_size;
}
void free_sys(ptr_t BlockPos)
{
    uint32_t header_size = sizeof(struct Memory_Ptr_Header);
    ptr_t *fullPtr = BlockPos - header_size;
    struct Memory_Ptr_Header * headPtr = (struct Memory_Ptr_Header *)fullPtr;
    uint32_t bytesSize = headPtr->size;
    uint8_t PoolType = headPtr->type;
    bytesSize += header_size;
    FreeMemory(PoolType, fullPtr, bytesSize);
    return ;
}